/*
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * openGauss is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 * http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * HTAPDeleteMap.cpp
 *
 * IDENTIFICATION
 * 	  src/gausskernel/storage/htap/HTAPDeleteMap.cpp
 *
 * -------------------------------------------------------------------------
 */

#include "htap_logger.h"
#include "htap_delete_map.h"

namespace htap {
HTAP_DECLARE_LOGGER(HTAPDeleteMap, HTAP)
// HTAPDeleteMap structure
HTAPDeleteMap::HTAPDeleteMap() : m_array(nullptr), m_numOfBits(0), m_bitsSigned(0), m_firstUnsignedIdx(0) {}

HTAPDeleteMap::~HTAPDeleteMap()
{
    m_array = nullptr;
    m_numOfBits = 0;
    m_bitsSigned = 0;
    m_firstUnsignedIdx = 0;
}

void HTAPDeleteMap::Destroy()
{
    if (m_array != nullptr) {
        pfree(m_array);
        m_array = nullptr;
        m_numOfBits = 0;
        m_bitsSigned = 0;
        m_firstUnsignedIdx = 0;
    }
}

bool HTAPDeleteMap::init(uint32_t numOfBits)
{
    if (numOfBits == 0) {
        HTAP_LOG_ERROR("HTAP delete map init failed");
        return false;
    }

    if (isInitialized()) {
        HTAP_LOG_ERROR("HTAP delete map already initialized");
        return false;
    }

    /* Initiate bitmap array */
    m_numOfBits = numOfBits;
    m_array = allocate();
    if (m_array == nullptr) { // allocation failed
        m_numOfBits = 0;
        m_bitsSigned = 0;
        m_firstUnsignedIdx = 0;
        return false;
    }

    /* Clear all bits */
    reset();
    return true;
}

bool HTAPDeleteMap::set(uint32_t bitIdx)
{
    if (!isInitialized()) {
        HTAP_LOG_ERROR("HTAPDeleteMap not initialized");
        return false;
    }

    if (bitIdx >= m_numOfBits) {
        HTAP_LOG_ERROR("HTAPDeleteMap index out of bound. bitIdx: (%d), m_numOfBits: (%d)", bitIdx,
                       m_numOfBits);
        return false;
    }

    m_array[index(bitIdx)] |= mask(bitIdx);
    if (m_bitsSigned < m_numOfBits) {
        m_bitsSigned++;
    }
    return true;
}

bool HTAPDeleteMap::reset(bool resetToZerro /* = true */)
{
    if (!isInitialized()) {
        HTAP_LOG_ERROR("HTAPDeleteMap not initialized");
        return false;
    }

    uint32_t arraySize = calculateArraySize();

    if (resetToZerro) {
        m_bitsSigned = 0;
        m_firstUnsignedIdx = 0;
        (void)memset_s(m_array, arraySize, 0, arraySize);
    } else {
        m_bitsSigned = m_numOfBits;
        m_firstUnsignedIdx = m_numOfBits;
        (void)memset_s(m_array, arraySize, 0xFF, arraySize);
    }

    return true;
}

unsigned char *HTAPDeleteMap::allocate() const
{
    uint32_t arraySize = calculateArraySize();
    unsigned char *buffer = (unsigned char *)palloc(sizeof(unsigned char) * arraySize);

    if (buffer == nullptr) { // allocation failed
        HTAP_LOG_ERROR("HTAPDeleteMap failed to allocate memory, number of bits: (%d), array size: (%d)",
                       m_numOfBits, arraySize);
    }

    return buffer;
}

void HTAPDeleteMap::copy(const HTAPDeleteMap &other)
{
    Assert(m_numOfBits == other.m_numOfBits);
    errno_t erc;

    uint32_t size = calculateArraySize();

    erc = memcpy_s(m_array, size, other.m_array, size);
    securec_check(erc, "\0", "\0");

    m_bitsSigned = other.m_bitsSigned;
}

bool HTAPDeleteMap::clear(uint32_t bitIdx)
{
    if (!isInitialized()) {
        HTAP_LOG_ERROR("HTAPDeleteMap not initialized");
        return false;
    }
    if (bitIdx >= m_numOfBits) {
        HTAP_LOG_ERROR("HTAPDeleteMap clear failed, index out of bound. bitIdx: (%d), m_numOfBits: (%d)", bitIdx,
                       m_numOfBits);
        return false;
    }

    m_array[index(bitIdx)] &= (~mask(bitIdx));
    if (m_bitsSigned > 0) {
        m_bitsSigned--;
    }

    return true;
}

bool HTAPDeleteMap::check(uint32_t bitIdx) const
{
    if (!isInitialized()) {
        return false;
    }
    if (bitIdx >= m_numOfBits) {
        return false;
    }

    return ((m_array[index(bitIdx)] & mask(bitIdx)) != 0);
}
}